
/***************************************************************************
                          object.cpp  -  description
                             -------------------
    begin                : Tue Aug 27 2002
    copyright            : (C) 2002 by Michiel Visser
    email                : 
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "expr.h"
#include "parser.h"
#include "mstl.h"

using namespace Expression;

namespace Sess
{

int StructIndex::update()
{		
	TypePtr s(session.getCurType());
  if (!!s)
  { if ((char *)(s->m_elems[m_index].m_name) != (char *)m_name)
    { m_index = s->findElem(m_name);
      if (m_index<0) 
      { return 1;
      }
    }
		session.m_curTypePtr = &(s->m_elems[m_index].m_type);
    return 0;
  }
  return 2;
}

TypePtr RegExpResultType;

void LocalVarVectorQueue::pop()
{	if (m_varCount) 
	{ Vector<VarValue> &v=*m_stack;
    for(int j=v.length();--j>=0;)
		{	v.decLengthWithoutDestroy(); // this makes it safe against garbage collection
			v[j].~VarValue();
		}
		m_stack.removeone();	
	}
}
#if 0
void LocalVarVectorQueue::indexCopy(int i, void *space)
{ if (!m_stack) new (space) NullObject(); else { (*m_stack)[i].m_value->duplicateIn(space); }
}
#endif
static bool s_fl = false;

bool operator==(const String &c, const StructElem &s) { return s.m_name==c; }
bool operator==(const String &c, const TypePtr &s) { return s->m_name==c; }

StructElem::StructElem(String name, TypePtr t): m_name(name), m_type(t) {}

static Object *containArray(OList &ol, int mylevel, int parentlevel)
{ Object *o=NEW_OBJ ListObject(ol);
	if (mylevel>parentlevel)
	{
		OList pol;
		pol.prepend(NEW_OBJ StringObject(" )"));
		pol.prepend(o);
		pol.prepend(NEW_OBJ StringObject("( "));
		return NEW_OBJ ListObject(pol);
	}
	return o;
}
Object *bracketize(Object *o)
{
	OList pol;
	pol.prepend(NEW_OBJ StringObject(" ]"));
	pol.prepend(o);
	pol.prepend(NEW_OBJ StringObject("[ "));
	return NEW_OBJ ListObject(pol);	
}

bool TypeFunc::assignsToTypeIdentifier(const Type *type) const { return false; }
bool TypeFunc::assignsToStructElement(TypePtr parent, int elem) const { return false; }
bool TypeSelection::assignsToTypeIdentifier(const Type *type) const { return type==(Type *)m_type; }
bool TypeAssignment::assignsToTypeIdentifier(const Type *type) const { return m_l->assignsToTypeIdentifier(type); }
bool TypeToStructElemAssignment::assignsToStructElement(TypePtr parent, int elem) const { return parent==m_parent && elem==m_elem; }
bool PreTypeSelection::assignsToTypeIdentifier(const Type *type) const { return type->m_name==m_typeName; }

bool TypeFunc::isPreTypeSelection() const { return false; }
bool PreTypeSelection::isPreTypeSelection() const { return true; }

enum
{
	levelTypeLiteral, // a, a.b, :a
	levelTypeAssignment,
	levelTypeStructConcat,
	levelType
};

Object *TypeAssignment::toArrayObject(int parentlevel, List<TypeFunc>::P &funcs) const
{
	OList arr;
	OList::P array(&arr);
	ADDA(m_l->toArrayObject(levelTypeLiteral, funcs));
	ADDSTR(" = ");
	ADDA(m_r->toArrayObject(levelType, funcs));
	return containArray(arr,levelType,parentlevel);
}
Object *TypeSelection::toArrayObject(int parentlevel, List<TypeFunc>::P &funcs) const
{
	return m_type->toArrayObject(parentlevel, funcs);
}
Object *PreTypeSelection::toArrayObject(int parentlevel, List<TypeFunc>::P &funcs) const
{
	OList arr;
	OList::P array(&arr);
	ADDSTR(m_typeName);
	return containArray(arr,levelTypeLiteral,parentlevel);;
}

Object *StructIndexing::toArrayObject(int parentlevel, List<TypeFunc>::P &funcs) const
{
	OList arr;
	OList::P array(&arr);
	ADDA(m_type->toArrayObject(levelTypeLiteral, funcs));
	ADDSTR(".");
	ADDSTR(m_index.m_name);
	return containArray(arr,levelTypeLiteral,parentlevel);
}
Object *StructConcat::toArrayObject(int parentlevel, List<TypeFunc>::P &funcs) const
{
	OList arr;
	OList::P array(&arr);
	ADDA(m_l->toArrayObject(levelTypeStructConcat, funcs)); //todo, parentlevel check?
	ADDSTR(" + ");
	ADDA(m_r->toArrayObject(levelTypeAssignment, funcs));
	return containArray(arr,levelTypeStructConcat,parentlevel);
}

Object *TypeToStructElemAssignment::toArrayObject(int parentlevel, List<TypeFunc>::P &funcs) const
{
	return m_subFunc->toArrayObject(parentlevel,funcs);
}

Object *Type::elemsToArrayObject(const List<TypeFunc> &funcs) const
{
	OList arr;
	OList::P array(&arr);
	List<TypeFunc>::P pfs(&funcs); 
	elemsToArray(array,pfs);
	return NEW_OBJ ListObject(arr);
}


void Type::elemsToArray(OList::P &array, List<TypeFunc>::P &funcs) const
{
	int l=m_elems.length(),i=0;
	if (l)
		for(;;)
		{	if (!!*funcs && (*funcs)->assignsToStructElement(TypePtr(this), i))
			{	TypeFunc &f=**funcs;
				funcs++;
				ADDA(bracketize(f.toArrayObject(levelType,funcs)));
			}
			else if (!!m_elems[i].m_type)
					ADDA(bracketize(m_elems[i].m_type->toArrayObject(levelType,funcs)));
			ADDSTR(m_elems[i].m_name);
			i++;
			if (i==l)
				break;
			ADDSTR(", ");
		}
	if (m_isDynamic)
		ADDSTR(", ...");
}

Object *Type::toArrayObject(int parentlevel, List<TypeFunc>::P &funcs) const
{
	OList arr;
	OList::P array(&arr);
	if (!!m_name)
	{
		if (!!*funcs && (*funcs)->assignsToTypeIdentifier(this))
		{	TypeFunc &f=**funcs;
			funcs++;
			ADDA(f.toArrayObject(parentlevel,funcs));
		}
		else
			ADDSTR(m_name);
	}
	else if (isMap())
	{
		TypePtr key (m_elems[0].m_type);
		if (!!key)
		{	ADDA(key->toArrayObject(levelTypeStructConcat,funcs));
		}
		else if (!!*funcs && (*funcs)->assignsToStructElement(TypePtr(this), 0))
		{	TypeFunc &f=**funcs;
			funcs++;
			ADDA(f.toArrayObject(levelTypeStructConcat,funcs));
		}
		ADDSTR(" => ");
		if (!!m_childType)
		{	ADDA(m_childType->toArrayObject(levelType,funcs));
		}
		else if (!!*funcs && (*funcs)->assignsToStructElement(TypePtr(this), -1))
		{	TypeFunc &f=**funcs;
			funcs++;
			ADDA(f.toArrayObject(levelType,funcs));
		}
		return containArray(arr,levelType,parentlevel);
	}
	else if (!!m_childType)
	{	ADDSTR(": ");
		ADDA(m_childType->toArrayObject(levelType, funcs));
	}
	else if (!!*funcs && (*funcs)->assignsToStructElement(TypePtr(this), -1))
	{	ADDSTR(": ");
		TypeFunc &f=**funcs;
		funcs++;
		ADDA(f.toArrayObject(levelType,funcs));
	}
	else
	{	ADDSTR("{ ");
		elemsToArray(array,funcs);
		ADDSTR(" }");
	}
	return NEW_OBJ ListObject(arr);
}

void Type::getElemNames(OList &o)
{
	int i;
	for(i=m_elems.length(); --i>=0;)
		o.prepend(NEW_OBJ StringObject(m_elems[i].m_name));
}

TypePtr TypeSelection::evaluate()
{ return m_type;
}

TypePtr PreTypeSelection::evaluate()
{ 
	TypePtr p(session.findType(m_typeName));
	if (!p)
	{ p = session.newTypeEntry(m_typeName);
  }
	this->~PreTypeSelection();
	new (this) TypeSelection(p);
	return p;
}

Object *TypeFunc::toArrayObject(int parentlevel, List<TypeFunc>::P &funcs) const { return 0; }

void TypeFunc::setSelfHolderPtr(List<TypeFunc>::P selfHolderPtr) {}
void TypeToStructElemAssignmentOnce::setSelfHolderPtr(List<TypeFunc>::P selfHolderPtr) { m_selfHolderPtr = selfHolderPtr; }

TypePtr TypeToStructElemAssignmentOnce::evaluate()
{
	TypeToStructElemAssignment::evaluate();
	m_selfHolderPtr->removeone();
	return TypePtr();
}

TypePtr TypeAssignment::evaluate()
{
	TypePtr lv(m_l->evaluate());
	if (!lv) return TypePtr();
	TypePtr rv(m_r->evaluate());
	if (!!rv)
	{	lv->set(*rv);	
	}
	return lv;
}

TypePtr StructConcat::evaluate()
{	
	TypePtr lv(m_l->evaluate());
	TypePtr rv(m_r->evaluate());
	if (!lv) return rv;
	if (!rv) return lv;
	TypePtr res;
	new (res) Type(*lv,*rv);
	return res;
}

TypePtr StructIndexing::evaluate()
{ 
	TypePtr t(m_type->evaluate());
	if (!t)
		return TypePtr();
	int i = m_index.m_index;
	if ((char *)t->m_elems[i].m_name != (char *)m_index.m_name)
  { 
    i=t->findElem(m_index.m_name);
    if (i<0) 
    { session.reportRuntimeError(String("Cannot find element '")+m_index.m_name+"' in a Type.");
      return TypePtr(); //error
    }
    m_index.m_index=i;
  }
	return t->m_elems[i].m_type;
}

TypePtr Type::getCopy(Type *from)
{	
	if (!!from)
	{	if(from->isAnonymous())
	  { TypePtr ns;
	    new (ns) Type(*from);
			return ns;
		}
		return TypePtr(from);
	}
	return TypePtr();
}
Type::Type( TypePtr key, TypePtr childType) : m_isDynamic(false), m_isSystem(false), m_childType(childType), m_elems(1) 
{ new (m_elems.space(0)) StructElem(String(),key);
}
void Type::set(const List<StructElem> &elems, bool isDynamic)
{	
	Vector<StructElem> v(elems.length());
	m_elems.take(v);
	m_isDynamic = isDynamic;
	int j=0;
	FOREACH(List<StructElem>, elems, e)
	{	new (m_elems.space(j++)) StructElem(e->m_name,e->m_type); // do not use getCopy or else "?[{[{[a.b]c}]d}]" will go wrong
	}
}

void Type::set(const Type &s)
{ 
	int lc;
	Vector<StructElem> v(lc=s.m_elems.length());
	m_elems.take(v);
	m_isDynamic = s.m_isDynamic; 
	while(--lc>=0)
	{	StructElem &e=s.m_elems[lc];
  	new (m_elems.space(lc)) StructElem(e.m_name, getCopy(e.m_type));
	}
	m_childType = getCopy(s.m_childType);
}

Type::Type(const Type &left,const Type &right): m_elems(left.m_elems.length()+right.m_elems.length()),m_isDynamic(right.m_isDynamic),m_isSystem(false)
{
	// todo: check childs are empty 
	int rc=right.m_elems.length();
	int lc=left.m_elems.length();
	while(--rc>=0)
	{	StructElem &e=right.m_elems[rc];
  	new (m_elems.space(rc+lc)) StructElem(e.m_name, getCopy(e.m_type));
	}
	while(--lc>=0)
	{	StructElem &e=left.m_elems[lc];
  	new (m_elems.space(lc)) StructElem(e.m_name, getCopy(e.m_type));
	}
}

int Type::findElem(String m)
{ int index=m_elems.findIndex(m);
  if (index>=0) 
	{	m_elems[index].m_name=m; //this makes sure the fast compare (pointer compare) works. // TODO: if ptr<ptr2 ptr=ptr2...!
		return index;
	}
  if (!m_isDynamic)
    return -1;
	int i=m_elems.length();
	m_elems.growByRealloc(i+1);
  new (m_elems.space(i)) StructElem(m);
  return i;
}

void Session::addFunc(EPtr e)
{	m_global.insertVar(e->toTyle(),NEW_OBJ ExprObject(e));
}

void Session::init(void (hashParser)(char *)) 
{
  m_hashParser = hashParser;
  m_firstStackVar.val=NullObject::obj();
  m_mainThread=m_curThread=new Thread();
	//if (s_fl)		print("Tyle session started.\n");
  EPtr e;
#define FUNC_EXPR(x) 	new (e) x##Expr(); addFunc(e);
#include "funcs.h"
	{	m_global.insertVar("tyleVersion",NEW_OBJ StringObject(TYLE_VERSION));
	}
	new (m_exprNull) ConstExpr(NullObject::obj());
  new (m_exprEmptyList) ConstExpr(NEW_OBJ ListObject());
  new (m_exprEmptyMap) ConstExpr(NEW_OBJ MapObject());
  {	int i,j;
  	for(i=0;i<4;i++)
  		new (m_exprNumbers[i]) ConstExpr(NEW_OBJ IntegerObject(i));
  	for(i=0;i<3;i++)
		{	new (m_exprDollarVars[i]) DollarVarExpr(i,i>0 ? (short('1')+i) : 0);
	  	for(j=0;j<4;j++)
				new (m_exprAbsDollarVars[i][j]) DollarVarExpr(j,'a'+i);
		}
	}

	TypePtr sub;
	new (sub) Type();
  List<StructElem> ses; // from last to first:
	new (ses.prependalloc()) StructElem("regs", sub);
	new (ses.prependalloc()) StructElem("len", sub);
	new (ses.prependalloc()) StructElem("pos", sub);
	TypePtr p;
	(new (p) Type())->set(ses,false);
	new (RegExpResultType) Type(p);
	sub->setSystem();
	p->setSystem();
	RegExpResultType->setSystem();
}

void Session::quit() 
{
	globalEnter();
	m_global.erase();
	m_firstStackVar.set(0);
	m_types.erase();
	ASSERT(!m_execStack)
	ASSERT(!m_curScope)
	FOREACH(ThreadList, m_threads, i) i->erase();	
	leave();
}

void Session::enter()
{ m_execCs.enter();
  if (!m_curThread || !m_curThread->isCurrent())
  { if(m_curThread)
	  {	m_curThread->m_curScope=m_curScope;
	  	m_curThread->m_execStack.take(m_execStack);
    	m_curThread->m_stack.take(m_stack);
    	m_curThread->m_curClosures = m_curClosures;
    	m_curThread->m_curTypePtr = m_curTypePtr;
			memcpy(m_curThread->m_firstPainters, m_firstPainters, sizeof(m_firstPainters));
		}
    m_curThread=*m_threads.finddata(GetCurrentThreadId());
    m_curScope = m_curThread->m_curScope;
    m_execStack.take(m_curThread->m_execStack);
    m_stack.take(m_curThread->m_stack);
    m_curClosures = m_curThread->m_curClosures;
    m_curTypePtr = m_curThread->m_curTypePtr;
		memcpy(m_firstPainters, m_curThread->m_firstPainters, sizeof(m_firstPainters));
		m_curThread->clearFirstPainters();
  }
}
void Session::execPushLvvq(LocalVarVectorQueue::Ptr q)
{	((LocalVarVectorQueue &)*q).push();
	execPush(q);
}
void Session::execPopLvvq()
{	((LocalVarVectorQueue &)*m_curScope).pop();
	execPop();
}

void Session::reportRuntimeError(String str)
{ EPtr v=m_global.findVar("reportRuntimeError");
  if (!!v)
  { pushStack(NEW_OBJ StringObject(str));
    {
			Object::HolderCP ovh;
   	 	v->evaluateToCopy(ovh);
			ovh.protectChilds();
    	ovh->evaluateToVoid();
		}
    popStack();
  }
}

void fileLogging(bool fl)
{
	s_fl=fl;
	if (fl)
	{	FILE *f;
		f=fopen("tylelog.txt","w");
		fclose(f);
	}
}

void print(char *format, ...)
{
	FILE *f;
	if (s_fl) f=fopen("tylelog.txt","a");
	va_list va;
  va_start(va, format);
  if (s_fl)	vfprintf(f, format, va);
  //if (dump       )   vprintf(   format, va);
  va_end(va);
	if (s_fl) fclose(f);
}

/*void GlobalVarVector::dumpVars()
{	for(int i=0; i<e_hashSize;i++)
	{	FOREACH(List<GlobalVariable>,hash[i],j)
			print(false,"%s ",(char *)j->getName());
		if (!!(hash[i])) print(false,",");
	}
	print(false,"\n");
}*/

void Session::stackString(const char *str, int len)
{	m_mainThread->setToCurrent(); 
  enter();
  {
    Object *r;
  	if (len>=0)
  		r=NEW_OBJ StringObject(str,len);
  	else
  		r=NEW_OBJ StringObject(str);
  	m_firstStackVar.set(r);
  }
  leave();
}

ExternObject *Session::evaluateToCopy(unsigned char *pos) 
{	
	ExternObject *result;
  m_evalCs.enter();
  m_mainThread->setToCurrent(); 
  enter();
  {
  	selectGlobal();
  	EPtr res;
  	if (s_fl) 
  		print("Evaluating: %s ... ", pos);
		ExternObject::List l;
		Object *space=l.prepend();
   	TyleParser(pos, res, space); 
   	if (!!res)
   	{	res->evaluateToPersistCopy(space);
   		m_firstStackVar.set(space->copy());
   	}
		result=attachFirstExtern(l);
  #ifdef MALLOC_COUNT
   	TRACEP(i,mcounts.variable)
   	TRACEP(i,mcounts.block)
   	TRACEP(i,mcounts.deletionCandidate)
  #endif
  	if (s_fl) 
  		print(" Done.\n", pos);
  }
	leave();
  m_evalCs.leave();
	return result;
}; 

ExternObject *Session::attachFirstExtern(ExternObject::List &from)
{	
	Sess::Session::m_externObjects.takeprependone(from);
	ExternObject *first=&*m_externObjects;
	ExternObject *pn=(first->m_holder=&m_externObjects)->pnext();
	if (pn) pn->m_holder = &first->m_holder->next();
	return first;
}

EPtr Scope::insertVar(String s, bool localFind) { ASSERT(0); }
bool Scope::isEmpty() const { return false; }

bool LocalVarVectorQueue::isEmpty() const { return m_varCount==0; }

EPtr SingleParamScope::findVar(String s, bool localFind)
{
	if (s==m_name)
	{	EPtr res;
		new (res) SingleParamExpr(session.m_funcLevel+m_depth,SingleParamScope::Ptr(this));
		return res;
	}
	return EPtr();
}

EPtr ParamSetScope::findVar(String s, bool localFind)
{
	int i=m_type->findElem(s);
	if (i>=0)
	{	EPtr res;
		new (res) ParamExpr(session.m_funcLevel+m_depth,m_type->m_elems[i].m_name);
		return res;
	}
	return EPtr();
}

void Session::schedule()    { leave(); enter(); }

EPtr Session::findOrInsert(String s, bool localFind) //todo: dollar
{ Scope *i;
	for(i=m_curScope; i; )
  { EPtr e ( i->findVar(s, localFind) );
    if (!!e) return e;
    if (localFind && m_curScope->isEmpty())
      return m_curScope->insertVar(s, localFind);
    i=i->m_father;
  }
  return m_global.getVarExpression(s);
}

void ThreadVars::GCPaint()
{ 
	FOREACH(List<StackVar>, m_stack, i) session.GCPaintObject(i->val);
	{	for(Painter *p=m_firstPainters[0];p;p=p->m_next)
		{	const Object *o=((SelfPainter *)p)->m_obj;
			if (o) session.GCPaintObject(o);
		}
	}
	{	for(Painter *p=m_firstPainters[1];p;p=p->m_next)
		{	const Object *o=((ChildrenPainter *)p)->m_obj;
			if (o) o->GCPaintMyChildren();
		}
	}
	{	for(Painter *p=m_firstPainters[2];p;p=p->m_next)
		{	FOREACH(OList, ((OListChildrenPainter *)p)->m_obj, i)
			{	session.GCPaintObject(*i);
			}
		}
	}
	if (!!m_curScope)
  { Scope *p=m_curScope;
    FOREACH(List<Scope::Ptr>, m_execStack,j)
    { p->GCPaint();
      p=*j;
    }
  }
}

void Scope::GCPaint() {}

void Thread::GCPaint()
{ 
	FOREACH(List<Object>,m_incoming,i)
	{	i->GCPaintMyChildren();
	}
	if (!!m_func)
		m_func->GCPaintMyChildren();
	ThreadVars::GCPaint();
}

void Session::GCPaint()
{ 
	if (m_firstStackVar.val) GCPaintObject(m_firstStackVar.val);
  if (m_keepMyChildren) m_keepMyChildren->GCPaintMyChildren();
	ThreadVars::GCPaint();
  m_global.GCPaint();
  FOREACH(ThreadList, m_threads,j) (*j)->GCPaint(); // it does not matter than curThread is done as well.
	while(!!m_childrenPaintStack)
	{	const Object *o = *m_childrenPaintStack;
		m_childrenPaintStack.removeone();
		o->GCPaintMyChildren();
	}
	FOREACH(ExternObject::List, m_externObjects, i) (*i)->GCPaintMyChildren();
}

Session session;

void LocalVarVectorQueue::GCPaint()
{
  FOREACH(List< Vector<VarValue> >, m_stack, i)
  { VarValue *l=(VarValue *)*i;
    for(int j=i->length();--j>=0;)
    { session.GCPaintObject(l[j].m_value);
    }
  }
}
void GlobalVarVector::GCPaint()
{
	List<GlobalVariable> *ls = hash.getLists();
	
	for(int i=hash.size; --i>=0; )
	{	FOREACH(List<GlobalVariable>, ls[i], j)
		{	session.GCPaintObject(j->m_value);
		}
	}
}
void GlobalVarVector::erase()
{
	List<GlobalVariable> *ls = hash.getLists();	
	for(int i=hash.size; --i>=0; )
	{	ls[i].erase();
	}
	new (m_names) MapObject(); //TODO: is m_names correctly deleted?
}

void LocalVarVectorQueue::push()
{ if (m_varCount)
  { /*VarValue *l = (VarValue *)*(new (m_stack) Vector<VarValue>(m_varCount));
  	for(int count=m_varCount; --count>=0;)
    { new (l+count) VarValue();
    }
    */
  	(new (m_stack) Vector<VarValue>(m_varCount))->init();
  	/*for(int count=m_varCount; --count>=0;)
    { ASSERT(&*((*m_stack)[count].m_value));
    }*/
  }
}

EPtr LocalVarVectorQueue::findVar(String s, bool localFind)
{	int i=vars.findindex(s);
	if (i>=0)
	{ if (localFind)
		{	EPtr res;
			LocalVarVectorQueue::Ptr p(this);
  		new (res) LocalBlockVarExpr(p,i);
			return res;
		}
		else
			return vars[i].expr; // todo: improve speed
	}
	return EPtr();
}

ClosureBinding::ClosureBinding(EPtr to, ClosureScope::Ptr scope): m_expr(to), m_scope(scope),
	m_vars(((ClosureScope &)*m_scope).m_count)
{
	int j=0;
	FOREACH(List<Closure>, ((ClosureScope &)*m_scope).m_closures, i)
	{
		new (m_vars.space(j++)) VarValue(i->expr->evaluateToOriginal(), *session.m_curTypePtr);	
	}
}

EPtr ClosureScope::findVar(String s, bool localFind)
{	Closure *e=m_closures.finddata(s);
	if (e)
	{ return e->m_intern;
	}
	int oldLevel=session.m_funcLevel;
	session.m_funcLevel=m_depth;
	EPtr r;
	for(Scope *i=m_father; i; i=i->m_father )
  { EPtr e = i->findVar(s, localFind);
    if (!!e)
		{	new (r) ClosureVarExpr(m_count++);
			new (m_closures.end()) Closure( s, e, r);
			break;
		}
  }
	session.m_funcLevel=oldLevel;
  return r;
}

EPtr LocalVarVectorQueue::insertVar(String s, bool localFind)
{
	EPtr res;
	LocalVarVectorQueue::Ptr p(this);
	int vi=vars.length();
 	Variable *v=new (vars.end()) Variable(s);
 	new (res) BlockVarExpr(p,vi);
	v->expr = res;
 	if (localFind)
		new (res) LocalBlockVarExpr(p,vi);
	return res;
}

GlobalVariable *GlobalVarVector::registerVar(String name, Object *v) 
{	insertName( name );
	return new (hash.getList(name)) GlobalVariable(name, v);
}

EPtr GlobalVarVector::findVar(String s)
{	
	GlobalVariable *sv=hash.find(s);
	if (sv)
	{ return sv->expr;
	}
	else return EPtr();
}

EPtr GlobalVarVector::getVarExpression(String s)
{
	EPtr res = findVar(s);
  if (!!res) return res;
  new (res) GlobalVarInitialExpr(s);
	return res;
}

void GlobalVarVector::insertVar(String s, Object *r)
{
 	GlobalVariable *v=registerVar(s,r);
	EPtr e;
	new (e) GlobalVarExpr(*v);
 	v->expr = e;
}

Thread::Thread(): m_thread(GetCurrentThread()), m_id(GetCurrentThreadId()), m_father(0)
{
	m_prio=GetThreadPriority(m_thread);
	session.m_threads.prepend(this);
}
Thread::Thread(Thread *father, Object *func): m_father(father), m_sem(true), m_func(func)
{
	//DuplicateHandle(GetCurrentProcess(),handle,GetCurrentProcess(),&pseudoHandle,0,FALSE,DUPLICATE_SAME_ACCESS);
	session.m_threads.prepend(this);
}
void Thread::setVars(HANDLE me, DWORD threadId)
{	m_thread = me;
	m_id = threadId;
	m_prio=GetThreadPriority(me);
}

Thread::~Thread()
{ //CloseHandle(pseudoHandle);
  session.m_threads.find(this).removeone();
}

ClosureScope::~ClosureScope() {}
SingleParamScope::~SingleParamScope() {}
ParamScope::~ParamScope() {}
Scope::~Scope() {}
ParamSetScope::~ParamSetScope() {}
LocalVarVectorQueue::~LocalVarVectorQueue() {}

#ifdef DEBUGLOGGING

void Session::doLog(Expr *expr)
{
	new (m_logQueue.put()) EPtr(expr);
}
void Session::getLog(void *space)
{
	OList ll;
	session.m_annotate=true;
	for(int i=m_logQueue.count(); --i>=0;)
	{
		ll.prepend(m_logQueue[i]->toArrayObject());
	}
	session.m_annotate=false;
	new (space) ListObject(ll);
}

#endif

TypePtr TypeToStructElemAssignment::evaluate()
{
	if (m_elem<0)
	{ 
		return m_parent->m_childType = m_subFunc->evaluate();
	}
	else
		return m_parent->m_elems[m_elem].m_type = m_subFunc->evaluate();
}

TypeFunc::~TypeFunc() {}
TypeToStructElemAssignment::~TypeToStructElemAssignment	() {}
TypeAssignment::~TypeAssignment() {}
TypeSelection::~TypeSelection() {}
StructIndexing::~StructIndexing() {}
StructConcat::~StructConcat() {}
PreTypeSelection::~PreTypeSelection() {}
TypeToStructElemAssignmentOnce::~TypeToStructElemAssignmentOnce() {}
}
